/**
 * 对 pages.h 的测试。
 */
#include "test_tools.h"
#include <mm/early_alloc.h>
#include <mm/pages.h>

/// 分配8MB
#define V_MEM_SIZE  (8UL << 20)

static void pages_h_test1(void)
{
    void *v_mem = aligned_alloc(V_MEM_SIZE, V_MEM_SIZE);
    unsigned long page_start = (VIRT_TO_PHY(v_mem) >> 12);
    unsigned long page_end = page_start + (V_MEM_SIZE >> 12);
    if (early_alloc_init(page_start, page_end, page_start, page_end, 12)) {
        LOG_TEST_FAIL("failed to initialize early_alloc!\n");
    } else {
        LOG_TEST_PASS("early_alloc initilaized!\n");
    }

    if (pages_init(page_start << 12, page_end << 12, 0)) {
        LOG_TEST_FAIL("failed to initialize pages' array!\n");
    } else {
        LOG_TEST_PASS("pages' array initilaized!\n");
    }

    /// 有效范围内的测试页号偏移。
    long valid_index[] = {
        563, 29, 703, 66, 694, 518, 1017, 806, 
        526, 413, 524, 887, 885, 589, 941, 755, 
        670, 157, 78, 679, 844, 22, 111, 654, 
        379, 906, 335, 539, 983, 221, 576, 262, 
        287, 584, 849, 912, 1008, 74, 384, 340, 
        955, 0, 958, 322, 169, 462, 511, 427, 
        1023, 988, 26, 108, 783, 813, 180, 964, 
        1018, 781, 402, 577, 1010, 928, 76, 280,
    };
    unsigned long valid_index_length =  \
        sizeof(valid_index) / sizeof(long);

    /// 有效范围外的测试页号偏移。
    long invalid_index[] = {
        -3334, -2853, -5647, 2985, 5147, -4072, 4166, 3882, 
        5274, -6776, -1017, -4910, -6318, -247, 8139, 4834, 
        -646, 4891, -6999, 3740, 2733, -4853, -1556, -1656, 
        6021, 5815, 5414, 4277, 4409, -4033, -6805, 5062, 
        1024, 3657, 4562, 2333, 4586, 8004, -1, -1935, 
        4272, 9041, 3194, -2500, 5294, -4576, -6554, -3381, 
        -6308, 5029, -4542, -3680, -4864, 4029, -1704, -6193, 
        -5327, -4665, -5211, 5755, -1309, -5330, 2587, 6256, 
    };
    unsigned long invalid_index_length =  \
        sizeof(invalid_index) / sizeof(long);

    /// 设置一部分为有效的页。
    if (set_pages_valid(
            page_start << 12, 
            (page_start << 12) + (V_MEM_SIZE >> 1)
        )
    ) {
        LOG_TEST_FAIL("failed to set pages' valid!\n");
    } else {
        LOG_TEST_PASS("pages' are set valid!\n");
    }

    unsigned long cnt = 0;
    unsigned long physical = 0;
    struct page_struct *page = NULL;
    /// 有效范围测试。
    for (cnt = 0; cnt < valid_index_length; cnt++) {
        physical = (page_start << 12) + (valid_index[cnt] << 12);
        page = physical_to_page(physical);
        if (page == NULL) {
            LOG_TEST_FAIL("cnt: %lu. failed to get page struct!\n", cnt);
            break;
        }
        if (!is_page_valid(page)) {
            LOG_TEST_FAIL("cnt: %lu. get an invalid page struct!\n", cnt);
            break;
        }
        if (get_page_physical(page) != physical) {
            LOG_TEST_FAIL("cnt: %lu. get an page struct "
                "with incorrect physical address!\n", cnt);
            break;
        }
    }

    if (cnt == valid_index_length) {
        LOG_TEST_PASS("valid pages test pass!\n");
    }

    /// 无效范围测试。
    for (cnt = 0; cnt < invalid_index_length; cnt++) {
        physical = (page_start << 12) + (invalid_index[cnt] << 12);
        page = physical_to_page(physical);
        if (is_page_valid(page)) {
            LOG_TEST_FAIL("cnt: %lu. get a valid page struct "
                "by an invalid physical address!\n", cnt);
            break;
        }
    }

    if (cnt == invalid_index_length) {
        LOG_TEST_PASS("invalid pages test pass!\n");
    }

    /// 上锁测试。
    for (cnt = 0; cnt < valid_index_length; cnt++) {
        physical = (page_start << 12) + (valid_index[cnt] << 12);
        page = physical_to_page(physical);
        if (!is_page_valid(page)) {
            LOG_TEST_FAIL("cnt: %lu. get an invalid page struct!\n", cnt);
            break;
        }
        
        if (page_struct_is_locked(page)) {
            LOG_TEST_FAIL("cnt: %lu. page struct is locked "
                "in the first place!\n", cnt);
            break;
        }

        lock_page_struct(page);
        if (!page_struct_is_locked(page)) {
            LOG_TEST_FAIL("cnt: %lu. failed to lock page struct!\n", cnt);
            break;
        }

        unlock_page_struct(page);
        if (page_struct_is_locked(page)) {
            LOG_TEST_FAIL("cnt: %lu. failed to release page struct!\n", cnt);
            break;
        }
    }

    if (cnt == valid_index_length) {
        LOG_TEST_PASS("page lock test pass!\n");
    }

    free(v_mem);
}

int main(void)
{
    printf("** pages.h test:\n");
    pages_h_test1();

    return 0;
}
